package com.vision.sales.collection.cl.ui;

import java.util.Date;
import java.util.HashSet;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.editor.client.Editor;
import com.google.gwt.editor.client.SimpleBeanEditorDriver;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.widget.core.client.Window;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.form.DateField;
import com.sencha.gxt.widget.core.client.form.SimpleComboBox;
import com.sencha.gxt.widget.core.client.form.TextField;
import com.sencha.gxt.widget.core.client.form.validator.MaxLengthValidator;
import com.sencha.gxt.widget.core.client.info.Info;
import com.vision.core.cl.BaseModule;
import com.vision.core.cl.Callback;
import com.vision.core.cl.ui.Notifications;
import com.vision.core.cl.ui.UI;
import com.vision.core.cl.ui.component.CompanyComboBox;
import com.vision.core.cl.ui.component.EnumComboBox;
import com.vision.core.cm.db.data.Company;
import com.vision.core.cm.util.DateUtils;
import com.vision.sales.cl.SalesServices;
import com.vision.sales.cl.event.CollectionCreatedEvent;
import com.vision.sales.cl.resource.SalesResources;
import com.vision.sales.cl.ui.component.CustomerComboBox;
import com.vision.sales.cm.data.PaymentType;
import com.vision.sales.cm.db.data.Collection;
import com.vision.sales.cm.db.data.Collection.FieldSpecs;
import com.vision.sales.cm.db.data.CollectionItem;
import com.vision.sales.cm.db.data.Customer;
import com.vision.sales.cm.db.data.SalesInvoice;

/**
 * 
 * @author Mark
 *
 */
public class CollectInvoicesWindow implements IsWidget, Editor<Collection> {
	
	interface Binder extends UiBinder<Widget, CollectInvoicesWindow> { }
	
	private static final Binder binder = GWT.create(Binder.class);
	
	@UiField Window window;
	@UiField VerticalLayoutContainer mainPanel;

	@UiField CompanyComboBox company;
	@UiField CustomerComboBox customer;
	@UiField TextField refNo;
	@UiField DateField date;
	@UiField SimpleComboBox<PaymentType> paymentType;
	@UiField TextField bank;
	@UiField TextField checkNo;
	@UiField DateField checkDate;
	@UiField TextField cashAccount;
	
	@UiField EditableCollectionItemGridPanel grid;
	
	@Ignore @UiField TextButton saveAndCreateBtn;
	@Ignore @UiField TextButton saveBtn;
	@Ignore @UiField TextButton cancelBtn;
	
	interface CollectionDriver extends SimpleBeanEditorDriver<Collection, CollectInvoicesWindow> { }
	
	private CollectionDriver driver = GWT.create(CollectionDriver.class);
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	@Override
	public Widget asWidget() {
		window = (Window) binder.createAndBindUi(this);
		window.getHeader().setIcon(SalesResources.INSTANCE.collections());
		
		driver.initialize(this);
		driver.edit(new Collection());
		
		loadData();
		
		date.setPropertyEditor(UI.datePropertyEditor());
		date.setValue(new Date());
		
		checkDate.setPropertyEditor(UI.datePropertyEditor());
		
		refNo.addValidator(new MaxLengthValidator(FieldSpecs.REF_NO_MAX));
		bank.addValidator(new MaxLengthValidator(FieldSpecs.BANK_MAX));
		checkNo.addValidator(new MaxLengthValidator(FieldSpecs.CHECK_NO_MAX));
		cashAccount.addValidator(new MaxLengthValidator(FieldSpecs.CASH_ACCOUNT_MAX));
		
		return window;
	}
	
	void loadData() {
		company.loadCompanies();
		customer.loadCustomers();
		
		Scheduler.get().scheduleDeferred(new ScheduledCommand() {
			@Override
			public void execute() {
				paymentType.select(0);
			}
		});
	}
	
	void edit(Collection collection) {
		driver.edit(collection);
		
		grid.grid.getStore().clear();
	}
	
	// UiFactory Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	@Ignore
	@UiFactory
	SimpleComboBox<PaymentType> initializePaymentTypeCombo() {
		EnumComboBox<PaymentType> pt = new EnumComboBox<PaymentType>(PaymentType.values());
		pt.addSelectionHandler(new SelectionHandler<PaymentType>() {
			@Override
			public void onSelection(SelectionEvent<PaymentType> event) {
				paymentTypeChanged(event);
			}
		});
		return pt;
	}
	
	@Ignore
	@UiFactory
	EditableCollectionItemGridPanel initializeCollectionItemGrid() {
		EditableCollectionItemGridPanel grid = new EditableCollectionItemGridPanel();
		return grid;
	}
	
	// Logic %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	@UiHandler("company")
	void companyChanged(SelectionEvent<Company> e) {
		Company selectedCompany = e.getSelectedItem();
		Customer selectedCustomer = customer.getValue();
		if (selectedCustomer == null || selectedCompany == null)
			return;
		
		loadSalesInvoicesForCollection(selectedCompany, selectedCustomer);
	}
	
	@UiHandler("customer")
	void customerChanged(SelectionEvent<Customer> e) {
		Customer selectedCustomer = e.getSelectedItem();
		Company selectedCompany = company.getValue();
		if (selectedCustomer == null || selectedCompany == null)
			return;
		
		loadSalesInvoicesForCollection(selectedCompany, selectedCustomer);
	}
	
	void paymentTypeChanged(SelectionEvent<PaymentType> e) {
		PaymentType paymentType = e.getSelectedItem();
		if (paymentType == null)
			return;
		
		boolean isCheck = paymentType == PaymentType.CHECK;
		
		bank.setEnabled(isCheck);
		checkNo.setEnabled(isCheck);
		checkDate.setEnabled(isCheck);
		
		if (!isCheck) {
			bank.setText("");
			checkNo.setText("");
			checkDate.setText("");
		}
	}
	
	@UiHandler("saveAndCreateBtn")
	void saveAndCreateClicked(SelectEvent e) {
		if (paymentType.getValue() == PaymentType.CHECK) {
			if (bank.getValue().isEmpty() || checkNo.getValue().isEmpty() || checkDate.getValue() == null) {
				Info.display("Check Payment Details", "Please enter check payment details.");
				return;
			}
		}
		
		doTheSave(new Callback<Collection>(window) {
			@Override
			protected void handleSuccess(Collection result) {
				BaseModule.fireEvent(new CollectionCreatedEvent(result));
				edit(new Collection());
			}
		});
	}
	
	@UiHandler("saveBtn")
	void saveClicked(SelectEvent e) {
		doTheSave(new Callback<Collection>(window) {
			@Override
			protected void handleSuccess(Collection result) {
				BaseModule.fireEvent(new CollectionCreatedEvent(result));
				window.hide(saveBtn);
			}
		});
	}
	
	void doTheSave(Callback<Collection> callback) {
		final Collection collection = driver.flush();
		if (driver.hasErrors())
			return;

		List<CollectionItem> collectionItems = grid.grid.getSelectionModel().getSelectedItems();
		if (collectionItems.isEmpty()) {
			Notifications.info("No sales invoice selected. Please select at least one.");
			return;
		}
		
		// Check that the invoice dates are before or on the same date as this
		// collection's date
		for (CollectionItem item : collectionItems) {
			Date invoiceDate = item.getSalesInvoice().getDate();
			if (DateUtils.isAfter(invoiceDate, collection.getDate())) {
				Notifications.info("One of the sales invoices has a date later than the collection's date.");
				return;
			}
		}
		
		collection.setCollectionItems(new HashSet<CollectionItem>(collectionItems));
		
		UI.mask(window, "Creating collection...");
		SalesServices.collectionSvc().create(collection, callback);
	}

	@UiHandler("cancelBtn")
	void cancelClicked(SelectEvent e) {
		window.hide(cancelBtn);
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	private void loadSalesInvoicesForCollection(Company company, Customer customer) {
		grid.grid.getStore().clear();
		
		grid.mask("Loading sales invoices for collection...");
		SalesServices.salesInvoiceSvc().getSalesInvoicesForCollection(company, customer, new Callback<List<SalesInvoice>>(grid) {
			@Override
			protected void handleSuccess(List<SalesInvoice> result) {
				for (SalesInvoice invoice : result) {
					CollectionItem item = new CollectionItem();
					item.setSalesInvoice(invoice);
					item.setCustomer(invoice.getCustomer());
					item.setAmount(invoice.getBalance());
					
					grid.grid.getStore().add(item);
				}
			}
		});
	}
	
}
